#include "ResourceManager.h"
#include "Exception.h"
#include "IContext.h"
#include "IFileSystem.h"
#include <cctype>


NS_B2D_BEGIN

#define _SAFE_GET_FACTORY(f, type, ret) \
do { \
	std::lock_guard<std::mutex> lock(mFactoriesMutex); \
	const auto it = mFactories.find(type); \
	if( it == mFactories.end() ) return ret(); \
	f = it->second; \
} while(0)
#define SAFE_GET_FACTORY(f, type) _SAFE_GET_FACTORY(f, type, ResourcePtr)
#define SAFE_GET_FACTORY2(f, type) _SAFE_GET_FACTORY(f, type, void)

void ResourceManager::registerFactory(IResourceFactory& factory)
{
	std::lock_guard<std::mutex> lock(mFactoriesMutex);

	const ObjectType& type = factory.getResourceType();
	mFactories[type] = &factory;
}

void ResourceManager::unregisterFactory(const ObjectType& resourceType)
{
	std::lock_guard<std::mutex> lock(mFactoriesMutex);

	const auto it = mFactories.find(resourceType);
	if( it != mFactories.end() )
		mFactories.erase(it);
}

ResourcePtr ResourceManager::getResource(const ObjectType& type, const StringId& name) const
{
	IResourceFactory* f = nullptr;
	SAFE_GET_FACTORY(f, type);
	return f->findResource(name);
}

ResourcePtr ResourceManager::getOrLoadResource(const ObjectType& type, const StringId& name)
{
	IResourceFactory* f = nullptr;
	SAFE_GET_FACTORY(f, type);
	return f->_getOrCreateFromFile(name);
}
ResourcePtr ResourceManager::createEmptyResource(const ObjectType& type, const StringId& name, bool addToCache)
{
	IResourceFactory* f = nullptr;
	SAFE_GET_FACTORY(f, type);
	return f->_createEmpty(name, addToCache);
}

void ResourceManager::addExistingResource(const ResourcePtr& res)
{
	if(!res) return;

	IResourceFactory* f = nullptr;
	SAFE_GET_FACTORY2(f, res->getResourceType());
	f->_addResourceToCache(res);
}

void ResourceManager::removeResource(const ObjectType& type, const StringId& name)
{
	IResourceFactory* f = nullptr;
	SAFE_GET_FACTORY2(f, type);
	f->_removeResourceFromCache(name);
}

void ResourceManager::removeAll(void)
{
	std::lock_guard<std::mutex> lock(mFactoriesMutex);
	for(auto& f : mFactories)
	{
		f.second->_clearCache();
	}
}

void ResourceManager::removeAllOfType(const ObjectType& t)
{
	IResourceFactory* f = nullptr;
	SAFE_GET_FACTORY2(f, t);
	f->_clearCache();
}

void ResourceManager::removeUnreferenced(void)
{
	std::lock_guard<std::mutex> lock(mFactoriesMutex);
	for(auto& f : mFactories)
	{
		f.second->_clearUnreferenced();
	}
}

void ResourceManager::removeUnreferencedOfType(const ObjectType& t)
{
	IResourceFactory* f = nullptr;
	SAFE_GET_FACTORY2(f, t);
	f->_clearUnreferenced();
}


NS_B2D_END